﻿/*************************************
 * Creator:SW-PeiYang
 * DateTime:2023/12/8 9:59:15
 * Description:<Description>
 * CopyRight:中广核研究院有限公司
 * ***********************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cpjit.SunnyPaine.Toolkit.Net.Sockets.Model
{
    /// <summary>
    /// 表示一段字节块。
    /// </summary>
    public class ByteBlock
    {
        private bool canAppend = true;
        private readonly List<byte> data;


        #region 公共属性
        /// <summary>
        /// 文本编码。
        /// </summary>
        public static Encoding Encoder { get; set; } = Encoding.UTF8;
        /// <summary>
        /// 是否小端转换。默认为true。
        /// </summary>
        public static bool LittleEndian { get; set; } = true;

        /// <summary>
        /// 当前已读取索引。
        /// </summary>
        public int ReadIndex { get; private set; }
        /// <summary>
        /// 当前已写入字节索引。
        /// </summary>
        public int WriteIndex { get; private set; }
        /// <summary>
        /// 字节快容量。
        /// </summary>
        public int Capacity { get; }
        /// <summary>
        /// 是否已重置。
        /// </summary>
        public bool HasReset { get; private set; } = true;
        #endregion


        #region 构造方法
        /// <summary>
        /// 使用默认的参数创建<see cref="ByteBlock"/>的实例。
        /// </summary>
        public ByteBlock() : this(1024 * 64)
        { }

        /// <summary>
        /// 使用指定的参数创建<see cref="ByteBlock"/>的实例。
        /// </summary>
        /// <param name="capcity"></param>
        public ByteBlock(int capcity)
        {
            this.Capacity = capcity;
            this.data = new List<byte>(capcity);
        }

        /// <summary>
        /// 使用指定的参数创建<see cref="ByteBlock"/>的实例。
        /// </summary>
        /// <param name="data"></param>
        public ByteBlock(byte[] data)
        {
            this.data = new List<byte>(data);
        }
        #endregion


        #region 私有方法
        private void Validate()
        {
            if (!this.canAppend)
            {
                throw new IndexOutOfRangeException("已手动结束追加内容，禁止继续追加内容。");
            }
        }
        #endregion


        #region 公共方法
        /// <summary>
        /// 写入数据。
        /// </summary>
        /// <param name="value"></param>
        public void WriteValue(short value)
        {
            byte[] datas = BitConverter.GetBytes(value);
            this.WriteValue(ByteBlock.LittleEndian ? datas : datas.Reverse().ToArray());
        }

        /// <summary>
        /// 写入数据。
        /// </summary>
        /// <param name="value"></param>
        public void WriteValue(int value)
        {
            byte[] datas = BitConverter.GetBytes(value);
            this.WriteValue(ByteBlock.LittleEndian ? datas : datas.Reverse().ToArray());
        }

        /// <summary>
        /// 写入数据。
        /// </summary>
        /// <param name="value"></param>
        public void WriteValue(long value)
        {
            byte[] datas = BitConverter.GetBytes(value);
            this.WriteValue(ByteBlock.LittleEndian ? datas : datas.Reverse().ToArray());
        }

        /// <summary>
        /// 写入数据。
        /// </summary>
        /// <param name="value"></param>
        public void WriteValue(bool value)
        {
            byte[] datas = BitConverter.GetBytes(value);
            this.WriteValue(datas);
        }

        /// <summary>
        /// 写入数据。
        /// </summary>
        /// <param name="value"></param>
        public void WriteValue(string value)
        {
            byte[] datas = ByteBlock.Encoder.GetBytes(value);
            this.WriteValue(datas);
        }

        /// <summary>
        /// 写入数据。
        /// </summary>
        /// <param name="value"></param>
        public void WriteValue(byte value)
        {
            this.Validate();
            this.data.Add(value);
            this.WriteIndex += 1;
            this.HasReset = false;
        }

        /// <summary>
        /// 写入数据。
        /// </summary>
        /// <param name="value"></param>
        public void WriteValue(byte[] value)
        {
            this.Validate();
            this.data.AddRange(value);
            this.WriteIndex += value.Length;
            this.HasReset = false;
        }

        /// <summary>
        /// 写入数据。
        /// </summary>
        /// <param name="value"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        public void WriteValue(byte[] value, int offset, int length)
        {
            for (int i = offset; i < length; i++)
            {
                this.Validate();
                this.data.Add(value[i]);
            }
            this.WriteIndex += length;
            this.HasReset = false;
        }

        /// <summary>
        /// 终止写入。
        /// </summary>
        /// <param name="write0">是否写入“\0”。true，写入；false，不写入。默认true。</param>
        public void EndWrite(bool write0 = true)
        {
            this.canAppend = false;
            if (write0)
            {
                this.data.Add(0);
            }
        }

        /// <summary>
        /// 读取数据。
        /// </summary>
        /// <returns></returns>
        public short ReadShort()
        {
            byte[] value = new byte[2];
            this.data.CopyTo(this.ReadIndex, value, 0, 2);
            short result = LittleEndian ? BitConverter.ToInt16(value, 0)
                                        : BitConverter.ToInt16(value.Reverse().ToArray(), 0);
            this.ReadIndex += 2;
            return result;
        }

        /// <summary>
        /// 读取数据。
        /// </summary>
        /// <returns></returns>
        public int ReadInt()
        {
            byte[] value = new byte[4];
            this.data.CopyTo(this.ReadIndex, value, 0, 4);
            int result = LittleEndian ? BitConverter.ToInt32(value, 0)
                                      : BitConverter.ToInt32(value.Reverse().ToArray(), 0);
            this.ReadIndex += 4;
            return result;
        }

        /// <summary>
        /// 读取数据。
        /// </summary>
        /// <returns></returns>
        public long ReadLong()
        {
            byte[] value = new byte[8];
            this.data.CopyTo(this.ReadIndex, value, 0, 8);
            long result = LittleEndian ? BitConverter.ToInt64(value, 0)
                                       : BitConverter.ToInt64(value.Reverse().ToArray(), 0);
            this.ReadIndex += 8;
            return result;
        }

        /// <summary>
        /// 读取数据。
        /// </summary>
        /// <returns></returns>
        public bool ReadBoolean()
        {
            byte[] value = new byte[1];
            this.data.CopyTo(this.ReadIndex, value, 0, 1);
            bool result = BitConverter.ToBoolean(value, 0);
            this.ReadIndex += 1;
            return result;
        }

        /// <summary>
        /// 读取数据。
        /// </summary>
        /// <returns></returns>
        public byte[] ReadByte(int length)
        {
            byte[] value = new byte[length];
            this.data.CopyTo(this.ReadIndex, value, 0, length);
            this.ReadIndex += length;
            return value;
        }

        /// <summary>
        /// 读取数据。
        /// </summary>
        /// <returns></returns>
        public string ReadString(int length)
        {
            byte[] value = new byte[length];
            this.data.CopyTo(this.ReadIndex, value, 0, length);
            string result = Encoder.GetString(value);
            this.ReadIndex += length;
            return result;
        }

        /// <summary>
        /// 读取数据。
        /// </summary>
        /// <returns></returns>
        public byte[] ToAarray()
        {
            return this.data.ToArray();
        }

        /// <summary>
        /// 重置。
        /// </summary>
        /// <returns></returns>
        public void Reset()
        {
            this.canAppend = true;
            this.ReadIndex = 0;
            this.WriteIndex = 0;
            this.data.Clear();
            this.HasReset = true;
        }
        #endregion
    }
}
